home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / demo / fun / mags / amigagadget21 / texte / prg.pcqilbmkurs / prg.pcqilbmkurs
Encoding:
Text File  |  1992-09-02  |  36.0 KB  |  1,085 lines

  1. #Titel Programmieren / PCQ-ILBM-Kurs
  2. #Logo gadget21:pinsel/AG.Prog
  3. #Font Losse 16
  4. #C31
  5.             PCQ - ILBM - Kurs
  6. #Font topaz 8
  7. #C10
  8.     wie man IFF-ILBM-Grafiken problemlos in PCQ-Programmen einlesen kann
  9.  
  10. #C21
  11. Es ist mal wieder Zeit für einen kleinen Ausflug in das Land von
  12. PCQ-Pascal. Und wie schon beim letzten Mal kam die Anregung zu diesem
  13. neuen Kursteil von
  14. #Y-5
  15. #C10
  16.                               Dennis Müller.
  17. #C21
  18. #Y-5
  19.  
  20. Thema des Kurses ist diesmal das Einladen von Grafiken im IFF-ILBM-Format
  21. per PCQ-Programmcode. Im Prinzip braucht sich dank hervorragender
  22. Library-Lösungen wie der SuperView-Library von Andreas R. Kleinert
  23. eigentlich kein Programmierer mehr mit den doch nicht ganz einfachen
  24. Detailfragen des IFF-Formates herumzuquälen. Dennoch kann man in
  25. Situationen kommen, in denen man sich nicht auf externe Lösungen verlassen
  26. kann. Darüberhinaus bietet das ILBM-Format auch einen kurzen Einblick in
  27. einfachste Kompressionsverfahren und eine Wiederholung der Grafikdarstellung
  28. des Amigas [siehe dazu auch schon den PCQ-Intuition-Kurs in früheren
  29. Gadget-Ausgaben]. Bevor an das Programmieren gedacht werden kann, müssen
  30. zunächst einige theoretische Grundlagen geklärt werden.
  31. #Seitenende
  32. #C31
  33. 1. Das IFF-Format
  34. #C21
  35.  
  36. IFF steht für "Interchange File Format", also für ein "Format zum
  37. Datenaustausch". Idee war es, verschiedenste Datentypen (Sound, Grafik,
  38. Text) in einem genormten Dateiformat anzubieten, so daß man problemlos
  39. eine Applikation an neue Formate anpassen kann. Prinzipiell funktioniert
  40. das IFF-Format so, daß die Daten in sogenannten "Chunks" zur Verfügung
  41. gestellt werden. Dabei können auch bei unterschiedlichen Datentypen
  42. gleiche Chunks verwendet werden - beispielsweise existiert ein "AUTH"-Chunk,
  43. in dem Hinweise zum Urheber des Datenfiles vermerkt sein können, unabhängig
  44. davon, ob es sich dabei um einen Text oder eine Grafik handelt.
  45.  
  46. Gemeinsam sind allen IFF-Dateien die ersten vier Bytes, die als Zeichen
  47. dargestellt die Information "FORM" beinhalten. Es folgt eine Integer-Zahl
  48. (vier Byte), die die Länge der gesamten nachfolgenden Chunks beinhaltet.
  49. Diese Zahl entspricht somit der Dateilänge abzüglich der ersten acht Byte.
  50. Um es zu veranschaulichen - ein Hexdump eines IFF-Files beginnt somit
  51. folgendermaßen (praktisch nachzuvollziehen durch "type Filename opt h") :
  52.  
  53. #C10
  54. 0000: 464F524D xxxxxxxx .....               FORMxxxx...
  55. #C21
  56.       F O  R M Bytezahl
  57.  
  58. Nun folgt eine Kennung, um was für ein Datenpaket es sich handelt (etwa
  59. "8SVX" für ein Soundsample), in unserem Fall handelt es sich um eine
  60. "Interleaved Bitmap", kurz "ILBM" [näheres dazu im 3.Kapitel]. Direkt
  61. an diese 4 Byte-Kennung schließen sich die einzelnen Datenchunks an, wobei
  62. man sich besser nicht auf irgendeine Reihenfolge verlassen sollte. Ein Chunk
  63. selbst ist dabei so aufgebaut, daß genau wie bei "FORM" zunächst die 4 Byte
  64. lange Kennung angegeben wird, gefolgt von einem Integer-Wert, der die Länge
  65. des Chunks in Byte angibt. Das hat den nicht zu verachtenden Vorteil, daß
  66. ein Programm auch beim Auftauchen unbekannter Chunks nicht hilflos dasteht.
  67. Ist nämlich dank des Integer-Wertes bekannt, wie lang der unbekannte Chunk
  68. ist, kann er zur Not einfach überlesen werden und das Programm beim nächsten
  69. Chunk weitermachen. Das IFF-File endet abrupt mit dem Ende des letzten
  70. Chunks. Es gibt keine gesonderte Schlußkennung, so daß man immer auch die
  71. Position im File im Auge haben sollte.
  72. #Seitenende
  73. #C31
  74. 2. Ein kleiner Trick
  75. #C21
  76.  
  77. Man sieht bereits jetzt, daß das Programm sich quasi wie ein Parser
  78. durch die Chunk-Reihen hangeln muß. Das geht natürlich auch von Diskette,
  79. man kann selbstverständlich ein IFF-File direkt vom Datenträger laden.
  80. Dabei besteht aber der Nachteil, daß das ganze spätestens bei gepackten
  81. Grafikdaten ziemlich langsam wird. Also lädt man - mit der Bytezahl-
  82. Information hinter "FORM" ausgestattet - einfach das ganze File in den
  83. Speicher und arbeitet es dort ab. Gerade in Pascal erreicht man so eine
  84. deutliche Leistungssteigerung. Das Problem dabei ist natürlich der
  85. Speicherplatz. Bei normalen Bildern der Auflösung 320*256 geht das
  86. noch, aber ein Bild in SuperHighRes mit 256 Farben verbraucht so selbst
  87. gepackt enorm viele Systemressourcen. Man muß sich also fragen, wozu man die
  88. IFF-Laderoutine einsetzen will. Sind Ressourcen vorhanden oder geht es nur
  89. um IFF-Dateien, die maximal 100 KByte groß sind, so empfiehlt es sich
  90. auf jeden Fall, das Bild zunächst in den Speicher zu laden. Ansonsten muß
  91. man eine Abwägung vornehmen und vielleicht die Daten vom Datenträger
  92. runterschauffeln. Im Rahmen dieses Kurses wird davon ausgegangen, daß sich
  93. die IFF-Datei im Speicher befindet. Doch auch da nutzen sie einem noch
  94. nicht allzu viel, hat man doch nur einen Address-Zeiger auf sie. Hier
  95. greift nun folgende Überlegung : wie wäre es, wenn wir so tun, als hätten
  96. wir nicht einfach eine Adresse, sondern - zumindest für die Bytezahlen -
  97. einen Zeiger auf einen Integerwert ? Also : statt einfach nur
  98.  
  99. #C10
  100. [...]
  101. VAR
  102.     datenbuffer :   Address;
  103.  
  104. [...]
  105.  datenbuffer:=AllocMem (filelength,MEMF_CLEAR+MEMF_PUBLIC);
  106. [...]
  107.  i:=DOSRead (fh,datenbuffer,filelength);
  108. [...]
  109. #C21
  110.  
  111. zu verwenden, einen zusätzlichen Zeiger, mit dem Integer-Werte leicht
  112. auszulesen sind, einzuführen. Und zwar zunächst so :
  113. #Seitenende
  114. #C10
  115. [...]
  116. VAR
  117.     datenbuffer     :   Address;
  118.     integerbuffer   :   ^Integer;
  119.  
  120. [...]
  121.  datenbuffer:=AllocMem (filelength,MEMF_CLEAR+MEMF_PUBLIC);
  122. [...]
  123.  i:=DOSRead (fh,datenbuffer,filelength);
  124.  integerbuffer:=datenbuffer;
  125. [...]
  126. #C21
  127.  
  128. Jetzt kann man mit                den ersten 32 Bit-Wert des Datenpakets
  129. #C10
  130. #Y-10
  131.                    integerbuffer^
  132. #C21
  133. auslesen. Doch da steht nun nur "ILBM", was als Integerwert eine völlig
  134. unbrauchbare Zahl ergibt. Praktischer wäre es, wenn man einen beliebigen
  135. Abstand zu Beginn des Datenpaketes wählen könnte. Dazu muß man wissen, daß
  136. das IFF-Format so aufgebaut ist, daß Integer-Werte stets an durch vier
  137. teilbaren Adressen stehen, eine Kombination "Integer, Short, Integer" kann
  138. somit nicht vorkommen. Wenn man aber mehrere Integer-Werte direkt
  139. hintereinander hat, hat man nichts anderes, als ein Array von Integer-
  140. Werten. In der Realität besteht natürlich kein Chunk nur aus Integer-Werten,
  141. vielmehr wird es auch Bytes und Shorts geben. Das ist jedoch unschädlich,
  142. da diese dann einfach überlesen werden, d.h. bei einer Kombination
  143. "Integer, Short, Short, Integer" spricht man zum Erreichen des zweiten
  144. Integer-Wertes einfach das dritte Element des Integer-Arrays an. Das zweite
  145. Element des Arrays besteht dabei aus zwei Short-Werten. Um auch diese
  146. korrekt lesen zu können, muß man sich neben dem Integer-Array auch eines
  147. Short- und bei entsprechendem Bedarf natürlich auch eines Byte-Arrays
  148. bedienen. Um das am Beispiel eines komplexeren Chunks darzustellen :
  149.  
  150. #C10
  151. Integer Short Short Integer Short Byte Byte Short Short Integer
  152. #C21
  153.  
  154. mit den Beispielwerten :
  155.  
  156. #C10
  157. 100000  20000 10000 200000  5000  10   20   2500  1250  400000
  158. #C21
  159.  
  160. Dieser experimentelle Chunk ist 24 Bytes lang. Die Variable
  161. #C10
  162. #Y-10
  163.                                                             datenbuffer
  164. #C21
  165. zeige auf den Anfang des Chunks. Nun richten wir uns ein Byte-, ein Short-
  166. und ein Integer-Array ein - wobei das Byte-Array maximal 24 Elemente
  167. enthalten muß, das Short-Array 12 (24/2) Elemente und das Integer-Array
  168. 6 (24/4) Elemente. Prinzipiell ist es völlig egal, ob man nun den
  169. Array-Bereich von 1 bis 24 (bzw. bis 12 oder 6) oder von 0 bis 23 (bzw. bis
  170. 11 oder 5) wählt, es hat sich aber eingebürgert, in solchen Fällen bei 0 zu
  171. beginnen. Somit sehen unseren Variablendefinitionen wie folgt aus :
  172.  
  173. #C10
  174. VAR
  175.     integerbuffer   :   ^ARRAY [0..5] OF INTEGER;
  176.     shortbuffer     :   ^ARRAY [0..11] OF SHORT;
  177.     bytebuffer      :   ^ARRAY [0..23] OF BYTE;
  178. #C21
  179.  
  180. Jeder Zeiger auf ein Array wird dann auf den Beginn des Chunks justiert :
  181. #C10
  182.  
  183.  integerbuffer:=datenbuffer;
  184.  shortbuffer:=datenbuffer;
  185.  bytebuffer:=datenbuffer;
  186. #C21
  187.  
  188. Und jetzt können ganz bequem die einzelnen Werte ausgelesen werden. Will
  189. man zum Beispiel den Wert der ersten Integer-Variable auslesen, erhält man
  190. mit                       für i den Wert 100000.                   liefert
  191. #C10
  192. #Y-10
  193.     i:=integerbuffer^[0];                        integerbuffer^[5]
  194. #C21
  195. den Wert 400000. Bei Short- und Byte-Werte funktioniert das genauso, nur
  196. daß man sich hier vor Augen halten muß, daß ein Integer-Wert zwei (fiktiven)
  197. Short-Werten im Short-Array entspricht. Will man also den ersten im
  198. Beispielchunk vorkommenden Short-Wert, vor dem sich nur ein Integer-Wert
  199. befindet, abfragen, so muß man einen Offset von 3 annehmen. Da unsere
  200. Tabelle aber bei 0 anfängt, bekommt man den Wert 20000 aus                .
  201. #C10
  202. #Y-10
  203.                                                            shortbuffer^[2]
  204. #C21
  205. Die nachfolgende 10000 erhält man mit Offset 4 (real : 4-1=3), also per
  206. #C10
  207. shortbuffer^[3]      shortbuffer^[9]
  208. #C21
  209. #Y-10
  210.                . Und                 ergibt natürlich 1250. Bei den
  211. Bytewerten funktioniert das alles analog, deshalb nur noch ein Beispiel
  212. zum Abschluß. Der Wert 10, der bytemäßig den Offset 14 hat, wird mit
  213.                 ausgelesen. Ist der Chunk dann komplett mittels dieses
  214. #C10
  215. #Y-10
  216. bytebuffer^[13]
  217. #C21
  218. kleinen Tricks analysiert, verschiebt man den datenbuffer um die Länge des
  219. Chunks (die man ja aus den zweiten 4 Byte bekommen hat), und wiederholt
  220. das Spielchen für den nächsten Chunk.
  221. #Seitenende
  222. #C31
  223. 3. Das IFF-ILBM-Format
  224. #C21
  225.  
  226. Nachdem sich bis jetzt alles auf einem ziemlich hohen Abstraktionsgrad
  227. abgespielt hat, wird es nun etwas konkreter. Wie aus dem 1.Kapitel bekannt
  228. ist, beginnt ein IFF-ILBM-File im Hexdump folgendermaßen :
  229.  
  230. #C10
  231. 0000: 464F524D xxxxxxxx 494C424D .....      FORMxxxxILBM...
  232. #C21
  233.       F O  R M Bytezahl I L  B M
  234.  
  235. Damit alleine kann natürlich noch kein Bild dargestellt werden. Die
  236. Informationen dazu stehen in eigenen Chunks, von denen es inzwischen
  237. Dutzende gibt - u.a. mehrere, die die Informationen für ColorCycling
  238. enthalten, den schon angesprochenen "AUTH"-Chunk und noch viel mehr
  239. oder weniger wichtige Chunks für andere Informationen zum Bild. Richtig
  240. wichtig sind für die simple Darstellung eines ILBM-Bildes eigentlich
  241. nur die folgenden :
  242. #Seitenende
  243. #C31
  244. 3. a) Der BMHD-Chunk
  245. #C21
  246.  
  247. Der "BitMapHeader"-Chunk enthält alle Informationen, die zum Öffnen
  248. eines Screens, bzw. eines RastPorts für das Bild notwendig sind, also
  249. Screenhöhe und -breite, die Anzahl der Bitplanes, usw. . Dieser Chunk
  250. ist unbedingt notwendig, damit das Bild dargestellt werden kann und
  251. er ist auch sinvollerweise der erste innerhalb der Datei - aber wie
  252. schon oben erwähnt sollte man sich nicht darauf verlassen. Nach der
  253. Kennung und dem Integer-Wert, der die Länge des Chunks angibt (im
  254. Normalfall $00000014 = 20 Bytes), folgen zunächst in Short-Länge
  255. die Breite und die Höhe des Bildes, gefolgt von einem Koordinatenpaar
  256. (immer noch jeweils in Short-Länge), das die linke obere Ecke des
  257. Ausschnitts kennzeichnet. Nun folgt die Tiefe des Screens als 1 Byte lange
  258. Variable. Das nächste Byte ist weniger interessant - ist es 1, wird eine
  259. "MaskPlane" den Grafikdaten angeschlossen. Weitaus wichtiger ist das nächste
  260. Byte, das festlegt, ob die Grafikdaten komprimiert oder unkomprimiert
  261. vorliegen. Ersteres ist der Fall, wenn das Byte den Wert eins hat. Zu den
  262. Unterschieden kommen wir im entsprechenden Kapitel. Das waren nun 3 Bytes
  263. in Folge, damit die nächste Short-Variable auf einer gerade Adresse liegen
  264. kann, folgt nun ein FÜllbyte. Die nun gerade Adresse enthält eine
  265. Short-Variable, die die Palette-Nummer der als "Hintergrund" zu verwendenden
  266. Farbe enthält. Das entspräche in einem Grafikprogramm wie DPaint etwa der
  267. Farbe, mit der man mit dem rechten Mausdruck zeichnet und ist in der Praxis
  268. normalerweise 0. Die nächsten beiden Bytes enthalten Werte, die das
  269. Größenverhältnis eines Pixels in x- und y-Richtung darstellen. Kann
  270. normalerweise auch völlig ignoriert werden. Last but not least folgen zwei
  271. Short-Variablen, die die Breite und die Höhe des Screens beinhalten. Somit
  272. sieht der BMHD-Chunk wie folgt aus :
  273.  
  274. #C10
  275. xxxx: 424D4844 00000014 aaaabbbb ccccdddd   BMHD....xxxxxxxx
  276. #C21
  277.       B M  H D Bytezahl < x><y > <le><te>
  278.  
  279. #C10
  280. xxyy: eeffgghh iiiijjkk llllmmmm            xxxxxxxxxxxx
  281. #C21
  282.       DeMaCoPa TColXAYA <sx><sy>
  283.  
  284. Damit die Informationen auch bequem ausgelesen werden können, empfiehlt
  285. es sich, auf den oben vorgestellten kleinen Trick zu rekurrieren. Zunächst
  286. einmal gilt es, die Identität und die Länge des Chunks zu ermitteln. Dazu
  287. verwenden wir die ebenfalls oben eingeführten Variablen. Zunächst zeigt der
  288. datenbuffer auf die Chunk-Kennung und ermöglicht es uns so auch, die Länge
  289. zu ermitteln (für ein eventuelles Überlesen).
  290.  
  291. #C10
  292.  integerbuffer:=datenbuffer;
  293.  datenbuffer:=Address(Integer(datenbuffer)+8);
  294.  { die 4-Byte-Kennung und die Bytezahl in Integerlänge überlesen }
  295.  bytebuffer:=datenbuffer;
  296.  shortbuffer:=datenbuffer;
  297.  datenbuffer:=Address(Integer(datenbuffer)+integerbuffer^[1]);
  298.  { den Chunk nun selbst überlesen, die Einsprungadressen stehen bereits in
  299.    bytebuffer und shortbuffer }
  300.  IF StrNEq (integerbuffer,"BMHD",4) THEN
  301.  BEGIN
  302.  
  303.    integerbuffer:=shortbuffer;
  304.    { nun wird auch der integerbuffer auf den eigentlichen Beginn des Chunks
  305.      (also hinter die Chunklänge) justiert }
  306.  
  307.   { Analyse des BMHD-Buffers }
  308.  END;
  309. #C21
  310.  
  311. Die Informationen des Chunks kann man nun aus folgenden Variablen
  312. auslesen :
  313.  
  314. Breite der Grafik   :
  315. Höhe der Grafik     :
  316. X-Wert der Ecke     :
  317. Y-Wert der Ecke     :
  318. Tiefe der Bitmap    :
  319. MaskPlane           :
  320. Kompression         :
  321. Hintergrundfarbe    :
  322. X-Aspekt            :
  323. Y-Aspekt            :
  324. Breite des Screens  :
  325. Höhe des Screens    :
  326. #Y-120
  327. #C10
  328.                         shortbuffer^[0]
  329.                         shortbuffer^[1]
  330.                         shortbuffer^[2]
  331.                         shortbuffer^[3]
  332.                         bytebuffer^[8]
  333.                         bytebuffer^[9]
  334.                         bytebuffer^[10]
  335.                         shortbuffer^[6]
  336.                         bytebuffer^[14]
  337.                         bytebuffer^[15]
  338.                         shortbuffer^[8]
  339.                         shortbuffer^[9]
  340. #C21
  341.  
  342. Mit diesen Werten ausgerüstet kann man rein theoretisch den Screen
  343. öffnen, es empfiehlt sich jedoch, damit bis zur Analyse des Chunks mit
  344. den eigentlichen Grafikdaten zu warten, da man vorher eventuell noch
  345. weitere Informationen - etwa zum verwendeten Viewmode - enthält.
  346. #Seitenende
  347. #C31
  348. 3. b) Der CAMG-Chunk
  349. #C21
  350.  
  351. Dieser Chunk enthält nur eine Information, nämlich einen eventuellen
  352. besonderen Viewmode des Screens. D.h. wenn die Grafik nicht im normalen
  353. Modus aufzubauen ist, sondern sich eines speziellen Grafikmodus wie
  354. HAM oder EXTRAHALFBRITE bedient, steht es hier oder sollte zumindest hier
  355. stehen. Manche ältere Grafikprogramme verfügen nicht über diesen Chunk,
  356. so daß man dann etwa eine 6-Plane-Grafik geliefert bekommt, ohne zu wissen,
  357. ob es sich jetzt um HAM oder Halfbrite handelt. Doch glücklicherweise
  358. speichern zumindest die heute gebräuchlichen Grafikprogramme diesen Chunk
  359. mit ab. Seine einzige Information :
  360.  
  361. Screen-Viewmode     :
  362. #Y-10
  363. #C10
  364.                         integerbuffer^[0]
  365. #Seitenende
  366. #C31
  367. 3. c) Der CMAP-Chunk
  368. #C21
  369.  
  370. Langsam aber sicher tasten wir uns an wirklich direkt die Grafik betreffende
  371. Informationen heran, nachdem nun erst der äußere Rahmen abgesteckt wurde.
  372. Der CMAP-Chunk enthält Informationen über die ColorMap, d.h. über die
  373. Farben der Grafik. Dabei gibt es zwei Möglichkeiten, die Zahl der
  374. verwendeten Farben zu berechnen :
  375.  
  376.  - einmal über die CAMG- und BMHD-Informationen unter Berücksichtigung der
  377.    Besonderheiten des HAM- und des EXTRAHALFBRITE-Modus, was bei ersterem
  378.    bedeutet, daß die letzten beiden Bitplanes der Bitmap keine originären
  379.    Farbinformationen sondern nur Modulationen der vorhandenen Farben
  380.    beinhalten (die Zahl der Farben entspricht hier also nicht 2^Depth
  381.    sondern 2^(Depth-2)), und bei letzterem, daß die letzte Bitplane nur die
  382.    Information beinhaltet, ob der an dieser Koordinate gesetzte Pixel in
  383.    voller und nur in halber Helligkeit gesetzt werden soll (Farbzahl =
  384.    2^(Depth-1))
  385.  - zum anderen über die Länge des Chunks, aus der, durch vier geteilt, man
  386.    die Farbzahl sicher errechnen kann
  387. Bis auf die Farbinformationen enthält dieser Chunk absolut nichts. Die
  388. einzelnen Farben werden dabei im betriebssystemtypischen RGB-Format
  389. kodiert. Das bedeutet, daß man je ein Byte für den Rot-, den Grün- und
  390. den Blau-Anteil der Farbe erhält. Damit die Adresse jeweils durch 4
  391. teilbar bleibt, ist der RGB-Kombination jeder Farbe ein Füllbyte
  392. vorangestellt, so daß eine Farbinformation das Format      hat. "f" steht
  393. #C10
  394. #Y-10
  395.                                                       fRGB
  396. #C21
  397. für das Füllbyte, die anderen Buchstaben jeweils für die ein Byte lange
  398. Farbanteilinformation. Die gewonnenen Werte können nun entweder um 4 Bit
  399. nach links verschoben                        der        Routine übergeben
  400. #Y-10
  401. #C10
  402.                       (bytebuffer^[x] shr 4)     SetRGB-
  403. #C21
  404. werden oder um 24 Bit nach links verschoben der          Routine von
  405. #C10
  406. #Y-10
  407.                                                 SetRGB32-
  408. #C21
  409. Kickstart 2.0.
  410. #Seitenende
  411. #C31
  412. 3. d) Der BODY-Chunk
  413. #C21
  414.  
  415. Die eigentlichen Grafikdaten findet man in diesem Chunk. Doch bevor man das
  416. gespeicherte Bild endlich auf den Screen bringen kann, gilt es erst
  417. herauszufinden, wie die Daten abgelegt sind - denn das ist im Gegensatz
  418. zu den anderen Chunks nicht einfach durch die Analysierung des Chunks selbst
  419. feststellbar. Vielmehr benötigt man die Informationen aus dem BMHD-Chunk.
  420. Ohne diese ist eine sinnvolle Verwertung der BODY-Daten unmöglich.
  421. Wichtigste Information ist das Byte, das festlegt, ob die Daten komprimiert
  422. sind oder nicht. Sind sie nicht komprimiert, ist das Einlesen einfach.
  423. Zunächst sollte man natürlich den Bildschirm nach den Vorgaben des BMHD- und
  424. des CAMG-Chunks zu öffnen. Dann muß man sich vor Augen halten, wie eine
  425. Grafik vom Computer aufgebaut wird. Dazu sei nochmals auf ältere Kursfolgen
  426. verwiesen. An dieser Stelle nur eine kurze Zusammenfassung : ein
  427. Bildschirm setzt sich aus mehreren übereinandergelegten Bitplanes zusammen.
  428. Die Zahl der Bitplanes bestimmt die Zahl der Farben (Farbzahl = 2^Zahl der
  429. Bitplanes). Dabei wird die Farbe eines Bildschirmpunktes (Pixel) durch die
  430. Kombination eines Bits an jeweils der gleichen Stelle der einzelnen
  431. Bitplanes bestimmt. Als Beispiel diene ein Screen mit 3 Bitplanes und damit
  432. 8 Farben. Das erste Byte der ersten Bitplane sehe (im Dualsystem notiert) so
  433. aus :
  434. #Y-10
  435. #C10
  436.                             %00100111
  437. #C21
  438. Das erste der zweiten :
  439. #Y-10
  440. #C10
  441.                             %01000100
  442. #C21
  443. Und der dritten :
  444. #C10
  445. #Y-10
  446.                             %11000110
  447. #C21
  448. Der erste Bildschirmpixel, also der an der Koordinate 0/0, hat nun den
  449. Farbwert %100 - das entsprechende Bit der dritten Bitplane zuerst, gefolgt
  450. von den anderen beiden. D.h. der Rechner setzt an 0/0 die Farbe, die mit
  451.                          definiert wurde. Der zweite Pixel hat die Farbe in
  452. #Y-10
  453. #C10
  454. SetRGB (ViewPort,4,....)
  455. #C21
  456. Palettennummer %110 (=6), der dritte die aus %001 (=1) und so weiter und so
  457. fort. Im unkomprimierten BODY-Chunk sind nun die Bytes der einzelnen
  458. Bitplanes "roh" abgelegt. Dabei kommen zunächst die Bytes der ersten
  459. Bildschirmzeile - und zwar zunächst die der ersten Bitplane, dann die
  460. der zweiten, etc. Es folgen die - ebenfalls nach Bitplanes sortierten -
  461. Bytes der zweiten Bildschirmzeile, dann die der dritten und so weiter bis
  462. zur Gesamthöhe der Grafik. Um die Daten auf den Bildschirm zu bringen, muß
  463. man somit nichts weiter tun, als zunächst den datenbuffer auf den Beginn
  464. der BODY-Daten zeigen zu lassen und dann nacheinander jeweils eine
  465. Bildschirmzeile dahin zu übertragen, wo sie in der Bitmap (nennen wir sie
  466. "bm^") unseres Screens hingehört. Dabei gilt für die Zieladresse des
  467. Datenschaufelns :
  468. #C10
  469.  
  470. datenziel:=Address(Integer(bm^.Planes[PlaneNr-1]+(BytesPerRow*(YOffset-1))));
  471. #C21
  472.  
  473. Übertragen werden müssen dabei                          Bytes pro Zeile.
  474. #C10
  475. #Y-10
  476.                                RASSIZE (Grafikbreite,1)
  477. #C21
  478. Nach Abschluß dieses Vorgangs befindet sich die Grafik auf dem Bildschirm,
  479. der Ladevorgang ist abgeschlossen. Komplizierter wird es nun natürlich
  480. bei komprimierten BODY-Daten. Dabei ist das Packverfahren denkbar simpel.
  481. Es basiert auf der Überlegung, daß in Grafiken sehr häufig einfarbige
  482. Flächen zu finden sind. Diese Flächen (beispielsweise in der Hintergrund-
  483. farbe 0) sehen nun nach dem oben dargestellten Darstellungsverfahren wie
  484. eine lange Abfolge des selben Bytes aus :
  485.  
  486. #C10
  487. %00000000 %00000000 %00000000 %00000000 %00000000 %00000000 %00000000
  488. #C21
  489.  
  490. Und das für jede Bitplane einmal. Diese Information sinnvoller und kürzer
  491. zu verpacken ist nun das Ziel des Packens und dafür hat man ein Verfahren
  492. entwickelt, das einfach und schnell zu handhaben ist und dennoch eine ganz
  493. gute Leistungsfähigkeit aufweist. Die Idee ist die, daß man zwischen
  494. Passagen, die in gepackter Form und Passagen, die in ungepackter Form
  495. vorliegen, unterscheidet. In der Praxis geschieht das durch ein
  496. Identifikationsbyte, das zum einen festlegt, ob die nachfolgenden Bytes
  497. gepackte oder ungepackte Informationen enthalten und das zum anderen auch
  498. die Länge des nachfolgenden Abschnittes (und damit auch den Abstand bis zum
  499. nächsten Identifikationsbyte) festlegt. Dabei muß man unterscheiden, ob
  500. der Wert des Identifikationsbytes kleiner oder größer als 128 ist (der Wert
  501. 128 selbst ist ohne Funktion). Ist er kleiner, indiziert das, daß die
  502. nachfolgenden Bytes nicht komprimiert sind, also direkt an ihr Ziel
  503. übertragen werden können. Die Bildschirmzeilen und Bitplanes sind übrigens
  504. genau wie im unkomprimierten BODY-Format angeordnet. Die Zahl, der dabei
  505. unverändert zu übernehmenden Bytes entspricht dem Wert des Identifikations-
  506. bytes+1. Liest man also etwa den Wert 40 aus, so gilt es, die nachfolgenden
  507. 41 Byte an das Ziel zu schaufeln. Danach folgt bis zum Ende der jeweiligen
  508. Bildschirmzeile ein neues Identifikationsbyte. Hat das Identifikations-
  509. byte nun einen Wert, der größer als 128 ist, so gilt es, den simplen
  510. Entpackvorgang durchzuführen. Dem Identifikationsbyte folgt nun nämlich
  511. ein einziges Informationsbyte. Dieses folgt an der momentanen Stelle
  512. des Grafik mehr als zweimal direkt aufeinander, um genau zu sein entspricht
  513. die Häufigkeit, mit der das Byte nun direkt nacheinander an die aktuelle
  514. Position in der Bildschirmgrafik anzuhängen ist, der Differenz zwischen
  515. 257 und dem Wert des Identifikationsbytes. Hat also das Identifikationsbyte
  516. den Wert 140, so hängt man an die aktuelle Position der Bildschirmgrafik
  517. 117mal das nachfolgende Informationsbyte an. Um es an einem weiteren
  518. Beispiel zu verdeutlichen, ein fiktiver Ausschnitt aus einem
  519. BODY-Chunk :
  520.  
  521. #C10
  522. ... %11011011 %00000000 %00000001 %00100110 %01110001 ...
  523. #C21
  524.  
  525. Das erste Identifikationsbyte hat den Wert 219, somit muß man den Wert des
  526. nachfolgenden Informationsbytes (=0) (257-219=) 38mal an die aktuelle
  527. Position anhängen. Es folgt ein weiteres Identifikationsbyte, das kleiner
  528. als 128 ist und somit aussagt, daß die beiden (1+1) nachfolgenden Bytes
  529. direkt übernommen werden sollen.
  530.  
  531. Dieses Spielchen geht solange, bis eine Bildschirmzeile abgearbeitet ist.
  532. Danach folgt dieselbe Zeile der nächsten Plane, etc. etc. Nun ist die Grafik
  533. komplett dargestellt.
  534. #Seitenende
  535. #C31
  536. 4. Listing
  537. #C21
  538.  
  539. Wie immer in diesem Kurs gibt es auch diesmal ein kleines Listing zur
  540. praktischen Demonstration des Stoffes. Es sei jedoch darauf hingewiesen, daß
  541. ich das Programm aus uralten Routinen zusammengestöpselt habe, die vor
  542. langer, langer Zeit einmal auf der Basis einer PD-Veröffentlichung von
  543. Fritjof Siebert und den Informationen der IFF-Entwickler-Disk von Commodore
  544. (u.a. Fish-Disk 185) entstanden sind. Die Routine "OpenScrn" dient vor allem
  545. der korrekten Darstellung älterer Grafiken, bei denen kein CAMG-Chunk
  546. vorhanden war. Bei neueren kann sich die mehr oder weniger ungefragte
  547. Bestimmung des Viewmodes manchmal kontrakproduktiv auswirken. Wie für das
  548. ganze Listing gilt : es ist ein Beispiel und es geht sicherlich alles
  549. optimaler und eleganter ....
  550.  
  551. #C10
  552. PROGRAM LoadIFF;
  553.  
  554. {
  555.   Demoprogramm für den IFF-PCQ-Kurs im AmigaGadget
  556.  
  557.   Funktion : kann vom CLI aus mit "IFFKurs Filename" aufgerufen werden
  558.              und zeigt dann das File "Filename" an, sofern es sich dabei
  559.              um ein IFF-ILBM-Bild handelt
  560.              es werden nur die allernotwendigsten Chunks unterstützt,
  561.              Overscan-Support oder ähnliches fehlt ebenso
  562.  
  563.   © 1995 by Andreas Neumann basierend auf einer Veröffentlichung von
  564.             Fritjof Siebert und den Informationen auf den
  565.             CATS-IFF-Entwickler-Disks
  566. }
  567.  
  568. {$I "Include:Exec/Exec.i" }
  569. {$I "Include:Hardware/IntBits.I" }
  570. {$I "Include:libraries/Dosextens.I" }
  571. {$I "Include:Graphics/Graphics.I" }
  572. {$I "Include:Graphics/Blitter.i" }
  573. {$I "Include:Graphics/GfxBase.i" }
  574. {$I "Include:Graphics/View.i" }
  575. {$I "Include:graphics/Pens.i" }
  576. {$I "Include:Graphics/Rastport.i" }
  577. {$I "Include:Intuition/intuition.i" }
  578. {$I "Include:Intuition/Intuitionbase.i" }
  579. {$I "Include:Utils/StringLib.i" }
  580. {$I "Include:Utils/Parameters.I" }
  581.  
  582.  
  583. TYPE
  584.     IFFTitles = (BMHD_f,CMAP_f,CAMG_f,BODY_f);
  585.  
  586.     BMHD = RECORD
  587.             width,
  588.             height      : SHORT;
  589.             depth       : BYTE;
  590.             left,
  591.             top         : SHORT;
  592.             masking     : BYTE;
  593.             transCol    : SHORT;
  594.             xAspect,
  595.             yAspect     : BYTE;
  596.             scrnWidth,
  597.             scrnHeight  : SHORT;
  598.            END;
  599.  
  600.     CMAP = RECORD
  601.             colorcnt    : SHORT;
  602.             red,
  603.             green,
  604.             blue        : ARRAY [0..255] OF BYTE;
  605.            END;
  606.  
  607.     CAMG = RECORD
  608.             viewType    : INTEGER;
  609.            END;
  610.  
  611.     IFFInfoType = RECORD
  612.                    IFFBMHD  : BMHD;
  613.                    IFFCMAP  : CMAP;
  614.                    IFFCAMG  : CAMG;
  615.                    IFFTitle : IFFTitles;
  616.                   END;
  617.  
  618.     IFFInfoTypePtr = ^IFFInfoType;
  619.  
  620.     IFFErrors = (iffNoErr,iffOutOfMem,iffOpenScreenfailed,
  621.                  iffOpenWindowFailed,iffOpenFailed,iffWrongIff,
  622.                  iffReadWriteFailed);
  623.  
  624.  
  625. CONST
  626.  
  627.     gfxname : String = ("graphics.library");
  628.  
  629.     { IFFError-Strings }
  630.  
  631.     IFFErrorStrings : ARRAY [iffNoErr..iffReadWriteFailed] OF String =
  632.                         ("No Error","Out of Memory","OpenScreen failed",
  633.                          "OpenWindow failed","Open Failed","Wrong Iff",
  634.                          "ReadWrite failed");
  635.  
  636.  
  637. VAR
  638.     IFFError    :   IFFErrors;
  639.     IFFInfo     :   IFFInfoType;
  640.     IFFName     :   String;
  641.     IFFScreen   :   ScreenPtr;
  642.     IFFWindow   :   WindowPtr;
  643.     IFFMes      :   IntuiMessagePtr;
  644.  
  645. {$A     XREF    _p%IntuitionBase    }
  646.  
  647.  
  648. FUNCTION Hoch (basis : INTEGER; exp : INTEGER) : INTEGER;
  649.  
  650. VAR h1 : INTEGER;
  651.     h2 : INTEGER;
  652.  
  653. BEGIN
  654.  h1:=1;
  655.  IF exp>0 THEN
  656.   FOR h2:=1 TO exp DO
  657.    h1:=h1*basis;
  658.  Hoch:=h1;
  659. END;
  660.  
  661.  
  662. FUNCTION GetIBase : IntuitionBasePtr;
  663.  
  664. BEGIN
  665. {$A
  666.         move.l  _p%IntuitionBase,d0
  667. }
  668. END;
  669.  
  670.  
  671. FUNCTION IsAGA (gb : GfxBasePtr) : BOOLEAN;
  672.  
  673. BEGIN
  674.  IF (gb^.ChipRevBits0 AND %100)=%100 THEN
  675.   IsAGA:=TRUE
  676.  ELSE
  677.   IsAGA:=FALSE;
  678. END;
  679.  
  680.  
  681. PROCEDURE MySetRGB (vp : ViewPortPtr ; nr , r , g , b : INTEGER ;
  682.                     gb : GfxBasePtr);
  683.  
  684. BEGIN
  685.  IF IsAGA (gb) THEN
  686.   SetRGB32 (vp,nr,r shl 24,g shl 24,b shl 24)
  687.  ELSE
  688.  SetRGB4 (vp,nr,(r shr 4),(g shr 4),(b shr 4));
  689. END;
  690.  
  691. PROCEDURE BufSkip (VAR bufptr : Address ; bytes : INTEGER);
  692.  
  693. BEGIN
  694.  bufptr:=Address(Integer(bufptr)+bytes);
  695. END;
  696.  
  697.  
  698. FUNCTION ReadILBM (name : String; VAR myscreen : ScreenPtr ;
  699.                    VAR mywindow : WindowPtr) : BOOLEAN;
  700.  
  701. VAR Compression,
  702.     MaskPlane,
  703.     contload        :   BOOLEAN;
  704.     LineLength,
  705.     LineWidth,
  706.     i,
  707.     j,
  708.     k,
  709.     len,
  710.     PictureLength   :   INTEGER;
  711.     PictureBuffer,
  712.     WorkBuffer,
  713.     HeaderBuffer    :   Address;
  714.     TextBuffer      :   String;
  715.     LONGBuffer      :   ^ARRAY [0..63] OF INTEGER;
  716.     SHORTBuffer     :   ^ARRAY [0..127] OF SHORT;
  717.     BYTEBuffer      :   ^ARRAY [0..255] OF BYTE;
  718.     InH             :   FileHandle;
  719.     IFFBitMap       :   BitMapPtr;
  720.  
  721.  
  722. PROCEDURE OpenScrn;
  723.  
  724. VAR nuscreen    :   NewScreen;
  725.     nuwindow    :   NewWindow;
  726.     i           :   INTEGER;
  727.  
  728. BEGIN
  729.  WITH NuScreen DO
  730.  BEGIN
  731.   width:=IFFInfo.IFFBMHD.scrnWidth;
  732.   IF width<IFFInfo.IFFBMHD.width THEN
  733.    width:=IFFInfo.IFFBMHD.width;
  734.   height:=IFFInfo.IFFBMHD.scrnHeight;
  735.   IF height<IFFInfo.IFFBMHD.height THEN
  736.    height:=IFFInfo.IFFBMHD.height;
  737.  
  738.   leftEdge:=IFFInfo.IFFBMHD.left;
  739.   topEdge:=IFFInfo.IFFBMHD.top;
  740.  
  741.   depth:=IFFInfo.IFFBMHD.depth;
  742.   viewModes:=0;
  743.   IF width>=640 THEN ViewModes:=ViewModes OR HIRES;
  744.   IF height>=400 THEN ViewModes:=ViewModes OR LACE;
  745.  
  746.   WITH IFFInfo.IFFCAMG DO
  747.    ViewModes:=ViewModes OR ViewType;
  748.  
  749.   IF ((depth=6) OR (depth=8)) AND (ViewModes=0) THEN
  750.   IF (IFFInfo.IFFCMAP.colorcnt=Hoch(2,depth-2)) THEN
  751.    ViewModes:=HAM;
  752.  
  753.   IF ((ViewModes AND HAM)=HAM) AND
  754.      (IFFInfo.IFFCMAP.colorcnt>Hoch(2,depth-2)) THEN
  755.    IFFInfo.IFFCMAP.colorcnt:=Hoch(2,depth-2);
  756.  
  757.   detailPen:=0;
  758.   blockPen:=0;
  759.   stype:=CUSTOMSCREEN_f+SCREENQUIET_f+SCREENBEHIND_f;
  760.   font:=NIL;
  761.   defaultTitle:=NIL;
  762.   gadgets:=NIL;
  763.   customBitMap:=NIL;
  764.  END;
  765.  myscreen:=OpenScreen (Adr(nuscreen));
  766.  IF myscreen=NIL THEN
  767.   IFFError:=iffOpenScreenfailed
  768.  ELSE
  769.  BEGIN
  770.  
  771.   WITH IFFInfo.IFFCMAP DO
  772.   BEGIN
  773.    FOR i:=0 TO (colorCnt-1) DO
  774.     MySetRGB (Adr(myscreen^.SViewPort),i,red[i],green[i],blue[i],GfxBase);
  775.   END;
  776.  
  777.   WITH nuwindow DO
  778.   BEGIN
  779.    leftEdge:=0;
  780.    topEdge:=0;
  781.    width:=IFFInfo.IFFBMHD.width;
  782.    height:=IFFInfo.IFFBMHD.height;
  783.    detailPen:=1;
  784.    blockPen:=0;
  785.    idcmpFlags:=MOUSEBUTTONS_f;
  786.    flags:=BORDERLESS+NOCAREREFRESH+RMBTRAP+ACTIVATE;
  787.    firstGadget:=NIL;
  788.    checkMark:=NIL;
  789.    title:=NIL;
  790.    screen:=myscreen;
  791.    bitMap:=NIL;
  792.    wtype:=CUSTOMSCREEN_F;
  793.   END;
  794.   mywindow:=OpenWindow (Adr(nuwindow));
  795.   IF mywindow=NIL THEN
  796.   BEGIN
  797.    CloseScreen (myscreen);
  798.    myscreen:=NIL;
  799.    IFFError:=iffOpenWindowFailed;
  800.   END;
  801.  END;
  802. END;
  803.  
  804.  
  805. PROCEDURE ReadQuick (mto : ADDRESS; Count : SHORT ; fake : BOOLEAN);
  806.  
  807. BEGIN
  808.  IF fake=FALSE THEN
  809.   CopyMem (WorkBuffer,mto,Count);
  810.  BufSkip (WorkBuffer,Count);
  811. END;
  812.  
  813.  
  814. PROCEDURE ReadSlow (ato : ADDRESS; Count : SHORT);
  815.  
  816. VAR kk,
  817.     scrRow,
  818.     bCnt    :   INTEGER;
  819.     inCode  :   BYTE;
  820.     ToPtr   :   ^ARRAY [0..9999] OF BYTE;
  821.     DPtr    :   ^ARRAY [0..254] OF BYTE;
  822.     RQBuf   :   BYTE;
  823.     j       :   SHORT;
  824.  
  825. BEGIN
  826.  ToPtr:=ato;
  827.  bCnt:=0;
  828.  WHILE bCnt<Count DO
  829.  BEGIN
  830.   DPtr:=WorkBuffer;
  831.   inCode:=DPtr^[0];
  832.   BufSkip (WorkBuffer,1);
  833.   IF inCode<128 THEN
  834.   BEGIN
  835.    CopyMem (WorkBuffer,Address(Integer(ato)+bCnt),inCode+1);
  836.    BufSkip (WorkBuffer,inCode+1);
  837.    Inc(bCnt,inCode+1);
  838.   END
  839.   ELSE
  840.    IF inCode>128 THEN
  841.    BEGIN
  842.     DPtr:=WorkBuffer;
  843.     RQBuf:=DPTr^[0];
  844.     BufSkip(WorkBuffer,1);
  845.     FOR j:=bCnt TO (bCnt+257-inCode-1) DO
  846.      ToPtr^[j]:=RQBuf;
  847.     Inc(bCnt,257-inCode);
  848.    END;
  849.  END;
  850. END;
  851.  
  852.  
  853. PROCEDURE CheckILBM;
  854.  
  855. BEGIN
  856.  IF StrNEq (TextBuffer,"FORM",4)=FALSE THEN
  857.   IFFError:=iffOpenFailed;
  858.  
  859.  IF (StrNEq (TextBuffer,"FORM",4)=TRUE) AND
  860.     (StrNEq(Address(Integer(TextBuffer)+8),"ILBM",4)=FALSE) THEN
  861.   IFFError:=iffWrongIFF;
  862. END;
  863.  
  864.  
  865. BEGIN
  866.  IFFInfo.IFFTitle:=IFFTitles(0);
  867.  IFFError:=iffnoErr;
  868.  myscreen:=NIL;
  869.  mywindow:=NIL;
  870.  PictureBuffer:=NIL;
  871.  PictureLength:=0;
  872.  contload:=FALSE;
  873.  InH:=DOSOpen (name,MODE_OLDFILE);
  874.  IF InH=NIL THEN
  875.   IFFError:=iffOpenfailed
  876.  ELSE
  877.  BEGIN
  878.   HeaderBuffer:=AllocMem (12,MEMF_CLEAR+MEMF_PUBLIC);
  879.   IF HeaderBuffer<>NIL THEN
  880.   BEGIN
  881.    len:=DOSRead (InH,HeaderBuffer,12);
  882.    IF len<>12 THEN IFFError:=iffReadWriteFailed;
  883.    TEXTBuffer:=HeaderBuffer;
  884.    LONGBuffer:=HeaderBuffer;
  885.    CheckILBM;
  886.  
  887.    PictureLength:=LONGBuffer^[1]-4;
  888.    FreeMem (HeaderBuffer,12);
  889.  
  890.    IF IFFError=iffNoErr THEN
  891.    BEGIN
  892.  
  893.     PictureBuffer:=AllocMem(PictureLength,MEMF_CLEAR+MEMF_PUBLIC);
  894.  
  895.     IF PictureBuffer=NIL THEN
  896.      IFFError:=iffOutofmem
  897.     ELSE
  898.     BEGIN
  899.      len:=DOSRead (InH,PictureBuffer,PictureLength);
  900.      IF InH<>NIL THEN BEGIN DOSClose (InH); InH:=NIL; END;
  901.      IF len<>PictureLength THEN
  902.       IFFError:=iffReadWritefailed
  903.      ELSE
  904.        contload:=TRUE;
  905.      WorkBuffer:=PictureBuffer;
  906.     END;
  907.    END;
  908.   END;
  909.  END;
  910.  IF contload THEN
  911.  BEGIN
  912.   WHILE (IFFError=iffNoErr) AND (contload) DO
  913.   BEGIN
  914.    TextBuffer:=WorkBuffer;
  915.    BufSkip(WorkBuffer,4);
  916.    IF StrNEq (TextBuffer,"BMHD",4) THEN
  917.    BEGIN
  918.     IFFInfo.IFFTitle:=IFFInfo.IFFTitle OR BMHD_f;
  919.     LONGBuffer:=WorkBuffer;
  920.     BufSkip(WorkBuffer,4);
  921.     j:=LONGBuffer^[0];
  922.     SHORTBuffer:=WorkBuffer;
  923.     BYTEBuffer:=WorkBuffer;
  924.     BufSkip(WorkBuffer,j);
  925.     WITH IFFInfo.IFFBMHD DO
  926.     BEGIN
  927.      width:=SHORTBuffer^[0];
  928.      height:=SHORTBuffer^[1];
  929.      left:=SHORTBuffer^[2];
  930.      top:=SHORTBuffer^[3];
  931.      depth:=BYTEBuffer^[8];
  932.      masking:=BYTEBuffer^[9];
  933.      MaskPlane:=(masking=1);
  934.      Compression:=(ByteBuffer^[10]=1);
  935.      transCol:=SHORTBuffer^[6];
  936.      xAspect:=BYTEBuffer^[14];
  937.      yAspect:=BYTEBuffer^[15];
  938.      scrnWidth:=SHORTBuffer^[8];
  939.      scrnHeight:=SHORTBuffer^[9];
  940.     END;
  941.    END
  942.    ELSE
  943.    BEGIN
  944.     IF StrNEq (TextBuffer,"CMAP",4) THEN
  945.     BEGIN
  946.      IFFInfo.IFFTitle:=IFFInfo.IFFTitle OR CMAP_f;
  947.      LONGBuffer:=WorkBuffer;
  948.      BufSkip(WorkBuffer,4);
  949.      i:=LONGBuffer^[0];
  950.      BYTEBuffer:=WorkBuffer;
  951.      BufSkip(WorkBuffer,i);
  952.      WITH IFFInfo.IFFCMAP DO
  953.      BEGIN
  954.       colorcnt:=i DIV 3;
  955.       j:=0;
  956.       FOR k:=0 TO colorcnt-1 DO
  957.       BEGIN
  958.        red[k]:=BYTEBuffer^[j];
  959.        green[k]:=BYTEBuffer^[j+1];
  960.        blue[k]:=BYTEBuffer^[j+2];
  961.        Inc(j,3);
  962.       END;
  963.      END;
  964.     END
  965.     ELSE
  966.     BEGIN
  967.      IF StrNEq (TextBuffer,"CAMG",4) THEN
  968.      BEGIN
  969.       IFFInfo.IFFTitle:=IFFInfo.IFFTitle OR CAMG_f;
  970.       LONGBuffer:=WorkBuffer;
  971.       BufSkip(WorkBuffer,8);
  972.       IFFInfo.IFFCAMG.viewType:=LONGBuffer^[1];
  973.      END
  974.      ELSE
  975.      BEGIN
  976.       IF StrNEq (TextBuffer,"BODY",4) THEN
  977.       BEGIN
  978.        IFFInfo.IFFTitle:=IFFInfo.IFFTitle OR BODY_f;
  979.  
  980.        OpenScrn;
  981.  
  982.        IF IFFError=iffNoErr THEN
  983.        BEGIN
  984.  
  985.         BufSkip (WorkBuffer,4);
  986.  
  987.         IFFBitMap:=myscreen^.SRastPort.BitMap;
  988.         LineLength:=RASSIZE(IFFInfo.IFFBMHD.width,1);
  989.         LineWidth:=IFFBitMap^.BytesPerRow;
  990.  
  991.         IF Compression THEN
  992.         BEGIN
  993.          FOR i:=0 TO (IFFInfo.IFFBMHD.height-1) DO
  994.          FOR j:=0 TO (IFFBitMap^.Depth-1) DO
  995.           ReadSlow (Address(Integer(IFFBitMap^.Planes[j])+(LineWidth*i)),
  996.                     LineLength);
  997.         END
  998.         ELSE
  999.         BEGIN
  1000.          FOR i:=0 TO (IFFInfo.IFFBMHD.height-1) DO
  1001.          FOR j:=0 TO (IFFBitMap^.Depth-1) DO
  1002.           ReadQuick (Address(Integer(IFFBitMap^.Planes[j])+(LineWidth*i)),
  1003.                      LineLength,FALSE);
  1004.          IF MaskPlane THEN
  1005.           ReadQuick (NIL,LineLength,TRUE);
  1006.         END;
  1007.  
  1008.        END;
  1009.        contload:=FALSE;
  1010.       END
  1011.       ELSE
  1012.       BEGIN
  1013.        LONGBuffer:=WorkBuffer;
  1014.        BufSkip (WorkBuffer,4);
  1015.        i:=LONGBuffer^[0];
  1016.        BufSkip (WorkBuffer,i);
  1017.       END;
  1018.      END;
  1019.     END;
  1020.    END;
  1021.   END;
  1022.  END;
  1023.  IF InH<>NIL THEN
  1024.   DOSClose (InH);
  1025.  IF PictureBuffer<>NIL THEN FreeMem (PictureBuffer,PictureLength);
  1026.  IF IFFError<>iffNoErr THEN
  1027.  BEGIN
  1028.   IF mywindow<>NIL THEN CloseWindow (mywindow);
  1029.   IF myscreen<>NIL THEN CloseScreen (myscreen);
  1030.   mywindow:=NIL;
  1031.   myscreen:=NIL;
  1032.  END;
  1033.  ReadILBM:=(iffError=iffNoErr);
  1034. END;
  1035.  
  1036.  
  1037. BEGIN
  1038.  IFFName:=AllocString(255);
  1039.  IF IFFName<>NIL THEN
  1040.  BEGIN
  1041.  
  1042.   GetParam(1,IFFName);
  1043.  
  1044.   IF StrLen (IFFName)>0 THEN
  1045.   BEGIN
  1046.    GfxBase := OpenLibrary(gfxname, 0);
  1047.    WRITELN ("\nIFF-Kurs für AmigaGadget - ein Demo-IFF-Lader");
  1048.    WRITELN ("written 1995 by Andreas Neumann":65,"\n");
  1049.    IF ReadILBM (IFFName,IFFScreen,IFFWindow) THEN
  1050.    BEGIN
  1051.     ScreenToFront (IFFScreen);
  1052.     REPEAT
  1053.      IFFMes:=Address(WaitPort(IFFWindow^.UserPort));
  1054.      IFFMes:=Address(GetMsg(IFFWindow^.UserPort));
  1055.     UNTIL IFFMes<>NIL;
  1056.     ReplyMsg (Address(IFFMes));
  1057.     ScreenToBack (IFFScreen);
  1058.    END;
  1059.  
  1060.    IF IFFWindow<>NIL THEN CloseWindow (IFFWindow);
  1061.    IF IFFScreen<>NIL THEN CloseScreen (IFFScreen);
  1062.    CloseLibrary (GfxBase);
  1063.    IF IFFError<>iffNoErr THEN
  1064.     WRITELN ("\n",IFFErrorStrings[IFFError],"\n");
  1065.   END;
  1066.   FreeString (IFFName);
  1067.  END;
  1068. END.
  1069. #Seitenende
  1070. #C21
  1071. So, das war's - in der Hoffnung, daß das Thema vielleicht den einen oder
  1072. anderen interessiert hat und ihm durch meine mehr oder weniger instruktiven
  1073. Ausführungen der Einstieg in die Welt der ILBM- und IFF-Files erleichtert
  1074. wurde. Wie immer gilt auch hier, daß Mitmenschen, die von der Materie
  1075. Ahnung haben, sich aufgefordert fühlen dürfen, mich auf Fehler, Unstimmig-
  1076. keiten und Falschinformationen hinzuweisen. Und für die, die noch Fragen zu
  1077. diesem oder einem anderen Thema haben, gilt natürlich, daß ich bemüht sein
  1078. werde, es im Rahmen meiner Möglichkeiten darzustellen und jedenfalls immer
  1079. eine offenes Ohr (und Nasenloch) für Fragen zu haben versuche. Bis dahin....
  1080.  
  1081. #Pinsel gadget21:pinsel/an rechts
  1082.  
  1083. #C10
  1084.                     Pascalcompiler haben kurze Beine.
  1085.